require("coxpcall")
require("cosmo")
require'zdc.showutil'
require'zdc.idutil'
require'zwsapi.uicfg'
local dfskey=zdc.fieldutil.dfskey
local util = require("zwsapi.util")
local html_forms = require("zwsapi.html_forms")
local actutil=require'zwsapi.actions.util'
local wrapper=require("zwsapi.wrapper")
module(..., package.seeall)

actions = {}

local function _map_type_to_htlm_type(n,k,t)
	--local val=n:__show_raw_k(k,t)
	local val
	if t.activate then
		val=n:__show_inh_k(k,t)
	else
		val=n:__show_val_k(k,t)
	end
	local rt={t[1],_fd=t,name=k,label=zdc.doc.get_doc(t._doc,'disp') or k,value=val}
	
	if t.proto=='concat' then
		rt[2]="textarea"
		rt.rows=3
	else
		rt[2]="text_field"
	end
	return rt
end
local function _field_type_esc(dal,t,v)
	if t=='textarea' then
		return dal:escape(v)
	else
		return dal:escape(v)
	end
end

local function _default_to_group(t,a)
	local i=math.floor(a)
	t[i]=t[i] or {}
	return t[i]
end
function _get_node_fileds_spec(user,dal,node,act,request,grpfn,mapfn)
	grpfn=grpfn or _default_to_group
	mapfn=mapfn or _map_type_to_htlm_type
	local tb,tbgrp={},{}
	local lvl1,lvl2=request.params.lvl1 or 1,request.params.lvl2
	local fds=node._fds
	for k,v in pairs(fds) do
		local l1=v[1]
		if l1 and ((l1>=lvl1) and (not lvl2 or l1<lvl2)) then
			tb[k]=mapfn(node,k,v)
			grpfn(tbgrp,l1)[k]=tb[k]
		end
	end
	for k,_ in pairs(node.__raw_v) do
		if not tb[k] and not fds[k] then
			local fd=dfskey(node._dfs,k)
			if fd then
				local l1=fd[1]
				if l1 and ((l1>=lvl1) and (not lvl2 or l1<lvl2)) then
					tb[k]=mapfn(node,k,fd)
					grpfn(tbgrp,l1)[k]=tb[k]
				end
			end
		end
	end
	local stb,ntb={},{}
	for k,v in pairs(tb) do
		table.insert(ntb,k)
		table.insert(stb,v)
	end
	local tbgrpidx={}
	for k,v in pairs(tbgrp) do
		local ntbg,stbg={},{}
		for k1,v1 in pairs(v) do
			table.insert(ntbg,k1)
			table.insert(stbg,v1)
		end
		table.insert(tbgrpidx,{grp=k,ntb=ntbg,stb=stbg})
	end
	table.sort(tbgrpidx, function(x,y) return x.grp < y.grp end)
	return stb,ntb,tbgrpidx
end
function make_html_show(dal,form_params, fields, field_names)
	-- Compile the field_spec if it hasn't already been compiled
	if not fields or not field_names then
		fields, field_names = compile_field_spec(form_params.field_spec)
	end

	table.sort(fields, function(x,y) return x[1] < y[1] end) -- sort by the first value (position)
	local html = ""

	for i, field in ipairs(fields) do
		local field_type = field[2]
		local label = field.label
		local name = field.name
		local template	= form_params.templates["SHADOW_"..field_type:upper()]
		
		field.label = label
		field.value=_field_type_esc(dal,field_type,field.value or form_params.values[name])
		
		field.html = cosmo.fill(template, field)

		html = html .. field.html
	end
	return html
end
function make_field_html(user,dal,node,act,request,sdn)
	if type(sdn)~='table' then return '' end
	local stb,ntb,grp=_get_node_fileds_spec(user,dal,sdn,act,request)
	local txtt
	if false then
		txtt=make_html_show(dal,{ 
					field_spec = nil,
					templates  = node.templates,
					translator = node.translator,
					values=sdn,},stb,ntb)
		txtt=cosmo.fill(node.templates.SHADOWFIELDS,{html_for_fields=txtt})
	else
		txtt=''
		local env={
			field_spec = nil,
			templates  = node.templates,
			translator = node.translator,
			values=sdn,
		}
		for i=1,#grp do
			local grpi=grp[i]
			local ttttt=make_html_show(dal,env,grpi.stb,grpi.ntb)
			if i > 1 then
				txtt=txtt.."<h4></h4>"
			end
			txtt=txtt..cosmo.fill(node.templates.SHADOWFIELDS,{html_for_fields=ttttt})
		end
	end
	return txtt
end
function make_html_show_subs(user,dal,node,subs,template,sdn)
	local html=''
	for i,v in ipairs(subs) do
		html = html .. cosmo.fill(template, {label=v,sub_url=dal:make_url(sdn.__id .. '/' .. v)})
	end
	return html
end
function make_subtable_show(user,dal,node,act,request,pto,list,all)
	local fields=_get_node_fileds_spec(user,dal,pto,act,request)
	table.sort(fields, function(x,y) return x[1] < y[1] end)
	local head='<h3>Sub Type: '..pto:__get_doc_disp()..'</h3>\n\n<table class="sortable"><thead><tr><td>ID</td>'
	for i, field in ipairs(fields) do
		head=head..'<td>'..field.label..'</td>'
	end
	head=head..'</tr></thead>'
	for i=1,#list do
		local sk=list[i]
		local sn=all[sk]
		local fill='<tr><td><a href="'..dal:make_url(sn.__id)..'">'..sk..'</a></td>'
		for i, field in ipairs(fields) do
			local sh=field._fd and field._fd[2]
			local v=sn:__show_val_k(field.name,field._fd)
			--print('a',type(v),v,field.name)
			sh=sh and sh._showS and sh:_showS(v)
			fill=fill..'<td>'..(sh or v or '')..'</td>'
		end
		head=head..fill..'</tr>'
	end
	return head..'</table>'
end
function make_sub_html(user,dal,node,act,request,sdn,deep)
	local allsubs,cfd
	if type(sdn)=='table' then
		allsubs=sdn:__get_child_all()
		cfd=sdn._cfd or {}
	else
		allsubs=dal:GetChildNodes(sdn)
	end
	local txt=''

	if cfd then
		for k,v in pairs(cfd) do
			local sn=allsubs[k]
			if sn then
				txt=txt..'<h3>Sub: <a href="'..dal:make_url(sn.__id)..'">'..sn:__get_doc_disp()..'</a></h3>\n\n'..make_node_html(user,dal,node,act,request,sn,deep)
				allsubs[k]=nil
			end
		end
	end
	local grp={}
	for k,v in pairs(allsubs) do
		local h=(v._pto and v.__pto_v) or v
		local t=grp[h] or {}
		table.insert(t,k)
		grp[h]=t
	end

	for h,v in pairs(grp) do
		if #v==1 then
			local sn=allsubs[v[1]]
			txt=txt..'<h3>Sub: <a href="'..dal:make_url(sn.__id)..'">'..sn:__get_doc_disp()..'</a></h3>\n\n'..make_node_html(user,dal,node,act,request,sn,deep)
		else
			table.sort(v,function (a,b)
				local ia,ib=tonumber(a),tonumber(b)
				if ia and ib then return ia<ib end
				if ia then return false end
				return a<b
			end)
			txt=txt..make_subtable_show(user,dal,node,act,request,h,v,allsubs)
		end
	end
	return txt
end

function make_node_html(user,dal,node,act,request,sdn,deep)
	deep=deep or 1
	local txtt=make_field_html(user,dal,node,act,request,sdn)

	local txt2=''
	if deep>0 then
		txt2=make_sub_html(user,dal,node,act,request,sdn,deep-1)
		if #txt2>1 then
			txt2=cosmo.fill(node.templates.SHADOWSUBS,{html_for_subs=txt2})
		end
	end
--[[
user,dal,node.templates.SHADOW_SUB_LINK
	local txtt={'<pre>'}
	zdc.showutil.ShowNode(sdn,function(...)
		for i=1,select('#',...) do
			table.insert(txtt,(select(i,...)))
		end
	end,true,1)
	table.insert(txtt,'</pre>')
	return title..node.markup.transform(table.concat(txtt,''), node)
--]]
	local fillarg={
		if_fields=cosmo.c(#txtt>1){shadow_field=txtt},
		if_subs=cosmo.c(#txt2>1){shadow_subs=txt2}
	}
	return cosmo.fill(node.templates.SHADOW_NODE,fillarg)
end

function build_seg_href(dal,id)
	local seg=zdc.idutil.GetSegment(id)
	local title=''
	local segadd=''
	for i=1,#seg do
		local s=seg[i]
		segadd=segadd .. s
		local n=dal:GetNode(segadd)
		title=title..'<a href="'..dal:make_url(segadd)..'">'..((n and zdc.doc.get_doc(n._doc,'disp')) or s)..'</a>/'
		segadd=segadd .. '/'
	end
	return title
end

function actions.show_content(user,dal,node,act,request)
	local sdn,msg=dal:GetNode(request.node_name)
	if not sdn then
		return 'not exist for '..request.node_name
	end
	local pro=''
	local title = ""
	if not sdn then
		pro= "<h1>"..request.node_name.."</h1>\n\n"..'Not find this node'
	end
	local deeplvl=tonumber(request.params.deeplvl) or 100

	local txtt=make_node_html(user,dal,node,act,request,sdn or request.node_name,deeplvl)

	local title=build_seg_href(dal,request.node_name,sdn)
	local fillarg={
		shadow_node=txtt,
		shadow_title='',
	}
	node.html_title=title
	node.name=request.node_name
	return pro .. cosmo.fill(node.templates.SHADOW,fillarg)
end

function actions.edit (user,dal,node,act,request)
	local sdn,msg=dal:GetNode(request.node_name)
	print(sdn,msg,request.node_name)
	if request.edit_new then
		if sdn then
			node:post_error("Node already exists.")
			node.inner_html = ""
			return node.wrappers.default(user,dal,node,act,request)
		end
		sdn,msg=dal:SureNode(request.node_name,nil,true)
		if not sdn then
			node:post_error("Node can't be create.")
			node.inner_html = ""
			return node.wrappers.default(user,dal,node,act,request)
		end
	end
	if not sdn then
		node:post_error("Node not exists.")
		node.inner_html = ""
		return node.wrappers.default(user,dal,node,act,request)
	end
	
	request.is_indexable = false

	etc = etc or {} -- additional parameters

	-- Add the editpage stylesheet
	node:add_javascript_link(dal:make_url("@ws/edit_scripts.js"))

	-- Select the parameters that should be copied
	local fields = {}

	fields.page_name = dal:dirify(node.name)  -- node name cannot be changed
	fields.user= request.params.user or ""
	fields.password=""
	fields.summary= request.params.summary or ""

	local honeypots = "" 
	math.randomseed(os.time())
	for i=0, (dal.config.NUM_HONEYPOTS_IN_FORMS or 0) do
		local field_name = "honey"..tostring(i)
		honeypots = honeypots.."\n"..cosmo.f([[$name			 = {$order, "honeypot"}]]){
										  order = string.gsub (tostring(math.random()*5), ",", "."),
										  name  = field_name,
									  }
		fields[field_name] = ""
	end

	-- Pre-compile the field spec
	local cfields, cfield_names
	if request.admin_edit then
		-- Setup the field spec
		cfields, cfield_names=html_forms.compile_field_spec(node[etc.shadow_config_ui or "shadow_config_ui"]..honeypots)
	else
		local wseditui=zwsapi.uicfg.SearchEdit(sdn)
		if wseditui then
			cfields, cfield_names=html_forms.compile_field_spec(wseditui..honeypots)
		else
			local function editmapfn(n,k,t)
				local val = request.params[k]
				if not val then
					val=n:__show_raw_k(k,t)
				end
				return {t[1], "text_field",_fd=t,name=k,label=zdc.doc.get_doc(t._doc,'disp') or k,value=val or ''}
			end
			cfields,cfield_names = _get_node_fileds_spec(user,dal,sdn,act,request,nil,editmapfn)
		end
	end
	--now add pto's inh values
	if sdn._pto and sdn.__pto_v.__get_inh_field then
		local ins={}
		for i, field in ipairs(cfields) do
			local fd=field._fd or sdn:__get_field_define(field.name)
			if fd and fd.proto then
				local pv=setmetatable({},{__index=field})
				pv[1]=field[1]-0.00001
				pv[2]='tip_area'
				pv.rows=1
				pv.editor_modules = {"resizeable", (fd.activate=='lua'and "validatelua") or nil}
				pv.name='__'.. fd.proto ..'_'..field.name
				pv.value=sdn.__pto_v:__get_inh_field(field.name) or ''
				table.insert(ins,pv)
			end
		end
		for i=1,#ins do
			table.insert(cfields,ins[i])
		end
	end
	for i, field in ipairs(cfields) do
		if not field.value then
			field.value=request.params[field] or sdn:__show_raw_k(field.name)
		end
		field.value=dal:escape(field.value)
		local editor_classes = {}
		if field.editor_modules then
			for j, module in ipairs(field.editor_modules) do
				local editor_module = require("zwsapi.editor." .. module)
				editor_module.initialize(user,dal,node,act,request)
				table.insert(editor_classes, "editor_" .. module)
			end

			local editor_class_txt = table.concat(editor_classes, " ")
			if not field.class or #field.class <= 0 then
				field.class = editor_class_txt
			else
				field.class = field.class .. ' ' ..editor_class_txt
			end
		end
		if cfield_names[i] == "category" then
			if field[2] == "select" then
				local _, category_hash = zwsapi.rootact.get_nav_bar(node, dal)
				local categories = {{display="		 ", value=""}}
				for id, _ in pairs(category_hash) do
					categories[#categories + 1] = {value=id, display=category_hash[id]}
				end
				table.sort(categories, function(x,y) return x.display < y.display end)
				field.options = categories
			end
		end
	end


	-- Make the form

	local form_params = {
		field_spec = nil, 
		values=fields,
	}
	local form = node:make_post_form(form_params, cfields, cfield_names)

	local captcha_html = ""
	if not request.user and dal.captcha then
		for _, field in ipairs(dal.captcha:get_fields()) do
			table.insert(form.field_list, field)
		end
		captcha_html = node.translator.translate_key("ANONYMOUS_USERS_MUST_ENTER_CAPTCHA")..dal.captcha:get_html()
	end

	local action="save"
	if request.edit_new then
		action = "create"
	end
	
	local title=build_seg_href(dal,sdn.__id)
	node.html_title=title
	node.name=sdn.__id

	node.inner_html = cosmo.f(node.templates.EDIT){
								if_preview		= cosmo.c(request.preview){
															preview = request.preview,
															summary = fields.summary
														},
								html_for_fields = form.html_for_fields,
								node_name		 = sdn.__id,
								post_fields	  = table.concat(form.field_list,","),
								post_token		= form.post_token,
								post_timestamp  = form.post_timestamp,
								action_url		= dal.config.BASE_URL,
								action			 = action,
								captcha			= captcha_html,
							}

	return node.wrappers.default(user,dal,node,act,request)
end

